/*******************************************************************************
* file  : rsa demo
* creat : apleilx
* data  : 2017/03/02
* @brief  	rsa 是一种非对称加密算法，加密解密KEY不同
*			此算法的应用传递过程：
*			A：生成密匙对，一个为公匙（用于传递），一个为私匙（自己持有）
*			B: 向A请求公匙
*			A：发送公匙给B
*			B: 用公匙加密数据发送给A
*			A：用私匙解密数据。用私匙加密数据发送给B
*			B: 用公匙解密数据
*******************************************************************************/
#include "common.h"
#include "crc_ext.h"
#include "mbedtls/rsa.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "bsp_api.h"
#include "os_obj.h"
#include "sys_task.h"
#include "mbedtls/platform.h"
#include "mbedtls/bignum.h"

/*
********************************************************************************
*                              function
*******************************************************************************/
#define DEV_RANDOM_THRESHOLD        32
int rsa_random_entropy_poll( void *, unsigned char *, size_t, size_t *);
static const char pers[] = "simple_rsa";
void dump_rsa_key(mbedtls_rsa_context *ctx);

extern uu8 * rsa_key_N;
extern uu8 * rsa_key_E;
extern uu8 * rsa_key_D;
extern uu8 * rsa_key_P;
extern uu8 * rsa_key_Q;
void dump_rsa_priv_key_export(mbedtls_rsa_context *ctx);

/*
********************************************************************************
*                              assert
*******************************************************************************/
#define assert_exit(cond, ret) \
    do { if (!(cond)) { \
        dbg_print("  !. assert: failed [line: %d, error: -0x%04X]\n", __LINE__, -ret); \
        goto cleanup; \
    } } while (0)

/*
********************************************************************************
*                              rsa_gen_signal
*******************************************************************************/
int rsa_gen_signal(void)
{
    int ret;
	uu32 tick;
	
    mbedtls_rsa_context *ctx;    //RSA密钥结构体
    mbedtls_entropy_context *entropy;
    mbedtls_ctr_drbg_context *ctr_drbg;
	
	dbg_print("\n\n");
	dbg_print("======================================\n");
	dbg_print("key gen pure\n");
	dbg_print("======================================\n");
	
	ctx = malloc(sizeof(mbedtls_rsa_context));
	entropy = malloc(sizeof(mbedtls_entropy_context));
	ctr_drbg = malloc(sizeof(mbedtls_ctr_drbg_context));
	
	tick = app_tick_get();
	
    mbedtls_entropy_init(entropy);		//初始化熵结构体
    mbedtls_ctr_drbg_init(ctr_drbg);	//初始化随机数结构体
	
    //rsa结构体初始化
    mbedtls_rsa_init(ctx);  
    						 
	// 填充方案OAEP //SHA256做散列算法
    mbedtls_rsa_set_padding(ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
	
	// 随机数生成器
	ret = mbedtls_entropy_add_source( 
		entropy, 
		rsa_random_entropy_poll,
		NULL, 
		DEV_RANDOM_THRESHOLD,
		MBEDTLS_ENTROPY_SOURCE_STRONG );
	
	assert_exit(ret == 0, ret);
	
    ret = mbedtls_ctr_drbg_seed(
		ctr_drbg, 
		mbedtls_entropy_func, 
		entropy, 
        (const uint8_t *) pers, 
		strlen(pers));				//根据个性化字符串更新种子
	
    assert_exit(ret == 0, ret);
    dbg_print("\n  . setup rng ... ok\n");
    dbg_print("\n  ! RSA Generating large primes may take minutes! \n");
	
	// 生成RSA密钥
    ret = mbedtls_rsa_gen_key(
		ctx, 
		mbedtls_ctr_drbg_random,	//随机数生成接口
		ctr_drbg,					//随机数结构体
		1024,						//模数位长度,即密匙长度、加密数据块长度
		65537);						//公开指数0x01001
    assert_exit(ret == 0, ret);                                    
    dbg_print("\n  1. RSA generate key ... ok\n");
    dump_rsa_key(ctx);  
	
	dbg_print("\n  2. RSA key export!\n");
	// 二进制大段格式，缓存长度大于实际长度时，数据在缓存尾部
	ret = mbedtls_rsa_export_raw(ctx, 
		rsa_key_N, 1024/8,
		rsa_key_P, 1024/8/2,
		rsa_key_Q, 1024/8/2,
		rsa_key_D, 1024/8,
		rsa_key_E, 16
		); 
		
	dbg_u8_print("N:", rsa_key_N,128, 130);
	dbg_u8_print("P:", rsa_key_P,128, 130);
	dbg_u8_print("Q:", rsa_key_Q,128, 130);
	dbg_u8_print("D:", rsa_key_D,128, 130);
	dbg_u8_print("E:", rsa_key_E,16, 16);
	
	// END
cleanup:
    mbedtls_ctr_drbg_free(ctr_drbg);	//释放随机数结构体
    mbedtls_entropy_free(entropy);		//释放熵结构体
    mbedtls_rsa_free(ctx);				//释放rsa结构体

	dbg_print("rsa key gen time : %d ms\n", app_tick_get() - tick);

	// 释放内存
	free(ctx);
	free(entropy);
	free(ctr_drbg);
	
    return ret;
}
